# -*- coding: utf8 -*-

from math import *

from google.appengine.ext import ndb

from statistics.word_statistic import *


class Word(ndb.Model):
    text = ndb.StringProperty(indexed=False)
    owner = ndb.IntegerProperty(indexed=False)

    def __hash__(self):
        return hash(self.text + str(self.owner))

    def __eq__(self, second):
        return self.text == second.text and self.owner == second.owner
    """ stores word info
    text: (ndb.StringProperty()) - which word is it
    owner: (ndb.IntegerProperty()) - index of who had written this word
    """


class WordGuessResult(ndb.Model):
    GUESS, FAIL, PUT_BACK, TIME_OUT = range(4)

    int_repr = {
        u'GUESS': GUESS,
        u'FAIL': FAIL,
        u'PUT_BACK': PUT_BACK,
        u'TIME_OUT': TIME_OUT
    }

    word = ndb.IntegerProperty(indexed=False)
    result = ndb.IntegerProperty(indexed=False)
    time_sec = ndb.FloatProperty(indexed=False)
    round_ = ndb.IntegerProperty(indexed=False)
    """ stores used word info
    word: (ndb.IntegerProperty) index of word
    result: (ndb.IntegerProperty()) guess result, must be in range(4)
    time_sec: (ndb.FloatProperty()) time from beginning of round when\
        word disappeared
    round_: (ndb.IntegerProperty()) id of round in which word was used
    """


class NormalWordGuessResult(object):
    pass


class Round(ndb.Model):
    player_explain = ndb.IntegerProperty(indexed=False)
    player_guess = ndb.IntegerProperty(indexed=False)
    #words = ndb.StructuredProperty(WordGuessResult, repeated=True)

    """ stores history of one round
    player_explain: (ndb.StringProperty())
    player_guess: (ndb.StringProperty())
    #words: (ndb.StringProperty(repeated=True)) words used in this round
    """


class GameId(ndb.Model):
    id_ = ndb.IntegerProperty()
    game_local = ndb.BooleanProperty(indexed=False)


class GameHistory(ndb.Model):
    players = ndb.StringProperty(repeated=True, indexed=False)
    rounds = ndb.StructuredProperty(Round, repeated=True, indexed=False)
    guess_results = ndb.StructuredProperty(WordGuessResult, repeated=True, indexed=False)
    words = ndb.StructuredProperty(Word, repeated=True, indexed=False)
    unused_words = ndb.StructuredProperty(Word, repeated=True, indexed=False)
    id_ = ndb.StructuredProperty(GameId)
    json_string = ndb.StringProperty(indexed=False)

    """ stores history of a game
    players: (ndb.StringProperty(repeated=True))
    rounds: (ndb.StructuredProperty(Round, repeated=True)) all played rounds
    guess_results: (ndb.StructuredProperty(WordGuessResult, repeated=True))
        results of guessing
    words: (ndb.StructuredProperty(Word, repeated=True))
    """

    @staticmethod
    def get_by_id(game_id):
        game_key = memcache.get('game_history_by_id_' + str(game_id))
        if game_key is not None:
            game = game_key.get()
        else:
            query_result = GameHistory.query().filter(
                GameHistory.id_.id_ == game_id)
            game = query_result.get()
            if game is None:
                return None
            memcache.set('game_history_by_id_' + str(game_id), game.key)
        return game

    def add_to_statistic(self):
        cnt_used_words = []
        total_time_words = []
        for i in range(len(self.words)):
            cnt_used_words.append(0)
            total_time_words.append(0)
        for round_id in range(len(self.rounds)):
            current_round = []
            for result in self.guess_results:
                if result.round_ != round_id:
                    continue
                word_guess_result = NormalWordGuessResult()
                word_guess_result.word = unicode(self.words[result.word].text)
                word_guess_result.result = int(result.result)
                word_guess_result.time_sec = float(result.time_sec)
                word_guess_result.id_ = int(result.word)
                current_round.append(word_guess_result)
            current_round.sort(key=lambda x: x.time_sec)
            last_time_sec = 0
            for word in current_round:
                current_time_sec = word.time_sec - last_time_sec
                last_time_sec = word.time_sec
                cnt_used_words[word.id_] += 1
                total_time_words[word.id_] += current_time_sec
                if word.result in (WordGuessResult.GUESS,
                                   WordGuessResult.FAIL):
                    if word.result == WordGuessResult.GUESS:
                        cur_stat_ttime = TTimeToCnt(
                            time_sec=int(ceil(total_time_words[word.id_])),
                            cnt_guess=1)
                        cur_stat_ltime_nattempt = LTimeAttemptNToCnt(
                            time_sec=int(ceil(current_time_sec)),
                            num_attempts=cnt_used_words[word.id_],
                            cnt_guess=1)
                    else:
                        cur_stat_ttime = TTimeToCnt(
                            time_sec=int(ceil(total_time_words[word.id_])),
                            cnt_fail=1)
                        cur_stat_ltime_nattempt = LTimeAttemptNToCnt(
                            time_sec=int(ceil(current_time_sec)),
                            num_attempts=cnt_used_words[word.id_],
                            cnt_fail=1)
                    word_stat = WordStatistic.query().filter(
                        WordStatistic.word == word.word).get()
                    if word_stat is None:
                        word_stat = WordStatistic(word=word.word)
                    histogram_update(word_stat.hist_ttime, cur_stat_ttime)
                    histogram_update(word_stat.hist_ltime_nattempt,
                                     cur_stat_ltime_nattempt)
                    word_stat.put()
